home *** CD-ROM | disk | FTP | other *** search
- /*
- * This program prints the files named in its argument list, preceding
- * the output with a table of contents. Each file is assumed to be C
- * source code (but doesn't have to be) in that the program searches
- * for the beginning and end of functions. Function names are added to
- * the table of contents, provided the name starts at the beginning of
- * a line. The function name in the output is double striken. White space
- * is inserted after every terminating '}' character. Thus functions
- * and structure declarations are nicely isolated in the output. The only
- * drawback to this is that structure initialization tables sometimes
- * produce large quantities of white space.
- *
- * Try it! You'll like it. (I call it cpr.c)
- *
- * written by: Paul Breslin
- * Human Computing Resources Corp.
- * 10 St. Mary St.
- * Toronto, Ontario
- * Canada, M4Y 1P9
- *
- * decvax!utcsrgv!hcr!phb
- */
-
- /*
- * The following options have been added. The `-n' option is used
- * to number source lines. Numbering starts at 1 (one) and is reset
- * to this number for each file. The `-o' option is used to put 1
- * (one) function on each page instead of multiple functions per page.
- * Line folding has been added.
- *
- * The `-l' option has been changed so that the blank space between
- * it and the following number has been eliminated. ("-l60" instead
- * of "-l 60")
- *
- * modified by: Lance E. Shepard
- * CCI & RIT (a lowly co-op)
- * Rochester, NY
- *
- * ...!rochester!ritcv!ritvp!les8070
- *
- * NOTE:
- * These modifications have been TESTED only ONCE. (And this
- * one time was under IDEAL CONDITIONS.) NO GUARANTEES!!
- *
- */
-
- /* This might be the last crack at this. I added the ability to read
- * standard input, removed dup2() calls to improve transportability,
- * and made sorting the table of contents an option (this was suggested
- * by the original author, Paul Breslin, who pointed out that people
- * (and VAXEN) will use the sorted or unsorted but probably not both).
- * So now there's only one table of contents (at the beginning), which
- * is sorted if the -s option is used. I wanted to make sorting the
- * default, but that would be inconsistant with the other options, so
- * if you're like me, alias it to cpr -s. I also robustized the command
- * line decoding, and set it up so that -l expects the length as the next
- * argument, but will accept it without an intervening space, so -l30
- * means the same as -l 30. The same is true of a new option, -w.
- * -w allows the user to specify the line width.
- *
- * The program should also grab fewer non-function constructs. It now
- * compares potential function names with the 'C' reserved words (from
- * "The C Programming Language", Kernighan and Ritchie, 1978) and
- * discards those that match. No, this doesn't take forever. Look
- * at the code.
- *
- * I agree with people who dislike 3 million options for one little
- * program, but plead that when reasonable defaults are provided it
- * needn't make a program cumbersome. Line width defaults to 132,
- * since we print mostly on our line printer, but the default is a
- * #define called WIDTH, so it's easy to change. Likewise for page
- * length (called LENGTH).
- *
- * I added a feature similar to that suggested by Rich Johnson at
- * Bell Labs, Whippany. Rather than substituting eight spaces for
- * every tab, it looks for the next tab stop in a string defining
- * tabs.
- *
- * I tested this rather thoroughly, but I also won't guarantee anything.
- *
- * Rick Wise
- * CALCULON Corp.
- * Rockville MD, 20850
- *
- * decvax!harpo!seismo!rlgvax!cal-unix!wise
- *
- */
-
-
- /* I fixed the lack of a page title on the table of contents page.
- * I made the table of contents only in sorted mode.
- * I made the function that deturmines weather a string is a function
- * or not much more intellegent. It now nolonger has to start at the
- * beginning of a line!!!
- * Overstrike now uses \r instead of \b for my printer's sake.
- *
- *
- * Blake McBride
- * 3900 SW 52 AVE #803
- * Pembroke Park, FL 33023
- */
- #include <stdio.h>
- #include <fcntl.h>
- /* #include <signal.h> */
-
- #define rindex strrchr
- #define mktemp(x) "cpr$.tmp"
-
- #define BP 0xC /* Form feed */
- #define MAX_S 256 /* Maximum string length */
- #define LENGTH 66 /* Default Page Length */
- #define WIDTH 132 /* Default page width */
- #define N_FILES 20 /* Maximum number of files */
- #define TOC_LEN 1024 /* Max no of T of C entries */
-
-
- /* The following string is the definition of tab stops. Every 'T' is a
- ** tab, any other character is not. It is currently defined as a tab
- ** every 8 spaces. The comment below helps if you want to modify this,
- ** each row being 0+n, 50+n, 100+n, and 150+n, where n is the number
- ** above the declaration. Don't try to number each row with a comment,
- ** because you'll notice that the '\'s make it one big string.
- */
-
- char *Rs(), *Datetime();
-
- /* 1 2 3 4 5
- 12345678901234567890123456789012345678901234567890 */
- char *TabDef = "\
- -------T-------T-------T-------T-------T-------T--\
- -----T-------T-------T-------T-------T-------T----\
- ---T-------T-------T-------T-------T-------T------\
- -T-------T-------T-------T-------T-------T-------T";
-
-
- FILE *File;
- int Braces; /* Keeps track of brace depth */
- int LineNumber; /* Count output lines */
- int PageNumber = 1; /* You figure this one out */
- int PageLength = LENGTH; /* Normal paper length */
- int PageWidth = WIDTH; /* normal page width */
- int PageEnd; /* Accounts for space at bottom */
- int InComment;
- int InString;
- int OnePerPage = 0;
- int NumLines = 0;
- int Number = 1;
- int WantSorted = 1; /* Sort the table of contents */
- char *Name; /* Current file name */
- char FunctionName[40];
- char *ProgName;
- char Todayv[45];
- char *STDIN = "\n"; /* special string pointer value to */
- /* flag a file as being stdin */
-
- main(argc, argv)
-
- int argc;
- char **argv;
- {
- register int i,
- nextf = 0; /* index into fname[] */
- char *fname[N_FILES]; /* file names to be worked on */
- /* char *ctime();
- long thetime, time();
- */
- ProgName = argv[0];
- /* thetime = time(0);
- Todayv = ctime(&thetime);
- */
- Datetime(Todayv);
-
- for (i = 1; i < argc; i++) {
- if (argv[i][0] == '-') {
- switch (argv[i][1]) {
- case 'l':
- if ( ! argv[i][2]) {
- if (++i >= argc)
- Usage();
- if ( ! ISdigit (argv[i][0]))
- Usage();
- PageLength = atoi (argv[i]);
- }
- else {
- if (!ISdigit(argv[i][2]))
- Usage();
- PageLength = atoi(&argv[i][2]);
- }
- break;
- case 'w':
- if ( ! argv[i][2]) {
- if (++i >= argc)
- Usage();
- if ( ! ISdigit (argv[i][0]))
- Usage();
- PageWidth = atoi (argv[i]);
- }
- else {
- if (!ISdigit(argv[i][2]))
- Usage();
- PageWidth = atoi(&argv[i][2]);
- }
- break;
- case 'n':
- NumLines = 1;
- break;
- case 'o':
- OnePerPage = 1;
- break;
- case 's':
- WantSorted = 1;
- break;
- case '\0':
- if (nextf >= N_FILES) {
- fprintf (stderr, "%s: too many files\n", argv[0]);
- exit (1);
- }
- fname[nextf++] = STDIN;
- break;
- default:
- Usage();
- break;
- }
- }
- else {
- if (nextf >= N_FILES) {
- fprintf (stderr, "%s: too many files\n", argv[0]);
- exit (1);
- }
- fname[nextf++] = argv[i];
- }
- }
-
- if ( ! nextf)
- fname[nextf++] = STDIN; /* if no files specified, use stdin */
-
- PageEnd = PageLength - (1 + PageLength / 20);
-
- StartTempFile();
-
- for (i = 0; i < nextf; i++) {
- if (fname[i] == STDIN) {
- File = stdin;
- Name = "standard input";
- }
- else {
- if( (File = fopen( Name = fname[i], "r" )) == NULL ) {
- fprintf (stderr, "%s: Can't open file \"%s\"\n",
- ProgName, Name );
- continue;
- }
- }
-
- List();
- if (File != stdin)
- fclose(File);
- }
-
- if( PageNumber > 1 || LineNumber > 0 )
- BreakPage();
-
- EndTempFile();
-
- DumpTableOfContents();
- DumpTempFile();
- Done();
- }
-
- Usage()
- {
- fprintf (stderr, "Usage: %s [-lpagelength] [-wpagewidth] [-n] [-o] [-s] file ...\n", ProgName);
- exit(1);
- }
-
- char *TempName;
- FILE *TempFile;
-
- StartTempFile()
- {
- /* extern char *mktemp(); */
-
- CatchSignalsPlease();
- TempName = mktemp("cprXXXXXX");
- if( (TempFile = fopen(TempName, "w")) == NULL )
- {
- fprintf (stderr, "%s: Can't open temp file!\n", ProgName);
- exit(1);
- }
- }
-
- EndTempFile()
- {
-
- fclose (TempFile);
- }
-
- DumpTempFile()
- {
- int fd,
- n;
- char buff[1024];
-
- if ((fd = open (TempName, O_RDONLY | O_RAW)) == -1) {
- fprintf (stderr, "%s: can't open temp file\n", ProgName);
- exit (1);
- }
- while (n = read (fd, buff, 1024)) {
- if (write (1, buff, n) == -1) {
- fprintf (stderr, "%s: write error (1)\n", ProgName);
- exit (1);
- }
- }
- }
-
- Done()
- {
- /*
- signal(SIGQUIT, SIG_IGN);
- signal(SIGHUP, SIG_IGN);
- signal(SIGINT, SIG_IGN);
- */
- if( TempName ) unlink( TempName );
- exit(0);
- }
-
- CatchSignalsPlease()
- {
- /*
- signal(SIGQUIT, Done);
- signal(SIGHUP, Done);
- signal(SIGINT, Done);
- */
- }
-
- List()
- {
- register int bp;
- char buffer[256];
-
- NewPage();
- NewFile();
- bp = Braces = 0;
- while( fgets(buffer, 256, File) != NULL )
- {
- Rs(buffer);
- if( bp )
- NewFunction();
- if( 1+LineNumber > PageEnd ) NewPage();
- if(!Braces && LooksLikeFunction(buffer))
- AddToTableOfContents();
- bp = PutLine(buffer);
- LineNumber++;
- }
- }
-
- PutLine(l)
- register char *l;
- {
- extern char *EndComment();
- extern char *EndString();
- char *expand(), *rindex();
- char *substr1();
- register char c;
- int bp;
- char *save;
- char *section, *p;
- int offset;
- char Digits[15];
- int Size;
- int pos;
-
- bp = 0;
- for( save = expand(l); c = *l; ++l )
- if( InComment )
- l = EndComment(l);
- else if( InString )
- l = EndString(l);
- else
- switch(c)
- {
- case '{':
- ++Braces;
- break;
-
- case '}':
- if( --Braces == 0)
- bp = 1;
- /* if (*(l+1) == ';') ++l;
- else bp = 1;
- * this is so no blank lines after structers */
- break;
-
- case '\'':
- ++l;
- break;
-
- case '"':
- InString = 1;
- break;
-
- case '/':
- if( *(l+1) == '*' )
- {
- InComment = 1;
- ++l;
- }
- break;
- }
-
- if (NumLines) {
- sprintf (Digits,"[%d] ", Number);
- Size = strlen(Digits);
- }
- else
- Size = 0;
-
- if (strlen(save) + Size > PageWidth) {
- section = substr1(save, 0, PageWidth - Size);
- if (section[strlen(section) - 1] != ' ')
- if (NULL == (p = rindex(section, ' ')))
- offset = strlen(section);
- else
- offset = p - section;
- else
- offset = strlen(section) - 1;
- section[offset] = NULL;
-
- if (NumLines) {
- fprintf (TempFile, "[%d] %s\n", Number++, section);
- }
- else {
- fprintf (TempFile, "%s\n", section);
- }
-
- pos = offset + 1;
- do {
- section = substr1(save, pos, pos + PageWidth - 8);
- if (strlen(save) - pos + 8 > PageWidth)
- if (section[strlen(section) - 1] != ' ')
- if (NULL == (p = rindex(section, ' ')))
- offset = strlen(section);
- else
- offset = p - section;
- else
- offset = strlen (section) - 1;
- else offset = strlen(section);
- section[offset] = NULL;
- /* if (section[strlen(section) - 1] == '\n')
- section[strlen(section) - 1] = NULL; */
- fprintf (TempFile, "C %s\n", section);
- if (++LineNumber > PageEnd)
- NewPage();
- } while ((pos += offset + 1) < strlen(save));
- }
- else {
- if (NumLines)
- fprintf (TempFile, "[%d] %s\n", Number++, save);
- else
- fprintf (TempFile, "%s\n", save);
- }
-
- return(bp);
- }
-
- char *
- EndComment(p)
- register char *p;
- {
- register char c;
-
- while( c = *p++ )
- if( c == '*' && *p == '/' )
- {
- InComment = 0;
- break;
- }
- return(p-1);
- }
-
- char *
- EndString(p)
- register char *p;
- {
- register char c;
-
- while( c = *p++ )
- if( c == '\\' )
- {
- ++p;
- continue;
- }
- else if( c == '"' )
- {
- InString = 0;
- break;
- }
- return(p-1);
- }
-
- NewFunction()
- {
- register int i;
-
- if( LineNumber > (PageLength * 3 / 4) )
- NewPage();
- else
- {
- if (!OnePerPage) {
- for( i=0; i < (PageLength/7); ++i ) putc ('\n', TempFile);
- LineNumber += PageLength/7;
- }
- else
- NewPage();
- }
- }
-
- #define HEADER_SIZE 3
-
- NewPage()
- {
- if( LineNumber > HEADER_SIZE )
- {
- if( PageNumber >= 0 ) ++PageNumber;
- BreakPage();
- LineNumber = 0;
- }
- if( LineNumber == 0 )
- PutHeader();
- }
-
- BreakPage()
- {
- putc (BP, TempFile);
- }
-
- PutHeader()
- {
- register int i, l, j;
-
- putc ('\n', TempFile);
- l = strlen(Name);
- for( j=0; j < 3; ++j )
- {
- fprintf (TempFile, "%s", Name);
- if( j < 2 )
- /* for( i=0; i < l; ++i ) putc ('\b', TempFile); */
- putc('\r', TempFile);
- }
- if( PageNumber > 0 )
- {
- for( i = (l+7)/8; i < 9; ++i ) putc ('\t', TempFile);
- fprintf (TempFile, "Page: %d\n\n", PageNumber);
- }
- else
- {
- for( i = (l+7)/8; i < 6; ++i ) putc ('\t', TempFile);
- fprintf (TempFile, "%s\n\n", Todayv);
- }
-
- LineNumber += HEADER_SIZE;
- }
-
- #define isidchr(c) (isalnum(c) || (c == '_'))
- #define isiechr(c) (isidchr(c) || c==' ' || c=='*' || c=='\t' || c=='\n')
-
- LooksLikeFunction(s)
- register char *s;
- {
- register char *p;
- char *save;
- int Cnt, nosl,nolp,norp,flg;
- char Digits[15];
- int AddOne = 0;
-
- if( InComment || InString ) return(0);
-
- p = FunctionName;
- save = s;
- nosl = nolp = norp = 0;
- flg = 1;
- for (; *s && flg ; s++) {
- switch (*s) {
- case '(':
- if (!nolp) nolp = 1;
- else return(0);
- break;
- case ')':
- if (nolp && !norp) norp = 1;
- else return(0);
- break;
- default:
- if (!nolp) {
- if (isiechr(*s)) {
- if (isidchr(*s)) *p++ = *s;
- else p = FunctionName;
- break;
- }
- else return(0);
- }
- if (!norp) {
- if (isiechr(*s) || *s == ',') break;
- else return(0);
- }
- if (Cmemb(*s," \t\n\r") && !nosl) break;
- if (*s == '/' && !nosl) {
- nosl = 1;
- break;
- }
- if (*s == '*' && nosl) {
- flg = 0;
- break;
- }
- return(0);
- }
- }
- if (nolp != 1) return(0);
- *p = '\0';
- /*
- * This will cause the function name part of the line to
- * be double striken.
- */
-
- if (NumLines) {
- sprintf (Digits,"[%d] ", Number);
- Cnt = strlen(Digits) + AddOne;
- while (Cnt-- > 0) putc (' ', TempFile);
- AddOne = 0;
- }
-
- while (*save && *save != '(') putc (*save++, TempFile);
- putc ('\r', TempFile);
-
- return(1);
- }
-
- char *Toc[TOC_LEN];
- int TocPages[TOC_LEN];
- int TocCount;
-
- AddToTableOfContents()
- {
- register int l;
- register char *p;
- char *malloc();
-
- if (TocCount >= TOC_LEN) {
- fprintf (stderr, "%s: too many table of contents entries\n", ProgName);
- exit (1);
- }
- l = strlen(FunctionName);
- p = Toc[TocCount] = malloc(l+1);
- strcpy(p, FunctionName);
- TocPages[TocCount] = PageNumber;
- ++TocCount;
- }
-
- NewFile()
- {
- register int i, l;
- char temp[20];
-
- if (TocCount >= TOC_LEN) {
- fprintf (stderr, "%s: too many table of contents entries\n", ProgName);
- exit (1);
- }
- Toc[TocCount] = (char *)malloc(130);
- sprintf (Toc[TocCount], "\n\tFile: %s ", Name);
- l = strlen(Toc[TocCount]) - 1;
- if( l < 64 )
- {
- i = (64 - l) / 8;
- for( l=0; l < i; ++l ) strcat(Toc[TocCount], "\t");
- }
- sprintf (temp, " Page %d\n", PageNumber);
- strcat(Toc[TocCount], temp);
- ++TocCount;
-
- if (NumLines)
- Number = 1;
- }
-
- DumpTableOfContents()
- {
- register int i, j, l;
-
- if( TocCount == 0 ) return;
-
- if (WantSorted)
- SortTableOfContents();
-
- Name = "Table of Contents";
-
- PageNumber = -1;
- LineNumber = 0;
- TempFile = stdout;
- NewPage();
-
- for( i=0; i < TocCount; ++i )
- {
- if( Toc[i][0] == '\n' )
- {
- if( (LineNumber + 5) > PageEnd )
- NewPage();
- printf("%s", Toc[i]);
- LineNumber += 2;
- continue;
- }
- if( ++LineNumber > PageEnd )
- NewPage();
- printf("\t\t%s ", Toc[i]);
- l = strlen(Toc[i]);
- for( j=l; j < 48; ++j ) putchar('.');
- printf(" %d\n", TocPages[i]);
- }
- putchar(BP);
- fflush (stdout);
- }
-
- SortTableOfContents()
- {
- register int i,
- tempint;
- char *tempchar;
- int flag;
-
- do {
- flag = 0;
- for (i = 0; i < TocCount - 1; i++) {
- if (Toc[i][0] == '\n' || Toc[i+1][0] == '\n')
- continue; /* don't sort across file names */
- if (strcmp (Toc[i], Toc[i+1]) > 0) {
- tempchar = Toc[i];
- Toc[i] = Toc[i+1];
- Toc[i+1] = tempchar;
- tempint = TocPages[i];
- TocPages[i] = TocPages[i+1];
- TocPages[i+1] = tempint;
- flag = 1;
- }
- }
- } while (flag);
- }
-
- /*
- * This is the function substr1(). The calling sequence is:
- *
- * substr1(string, startpos, endpos).
- *
- * The function returns a pointer to a static string (written over -
- * on subsequent calls) which is a substring of the string `string'
- * starting at `startpos' (the first position is 0 (zero)) and ending
- * at `endpos' (non-inclusive). All arguments must be present or
- * strange things happen with the system stack.
- *
- * An example of the use is:
- *
- * x = substr1(string, 2, 5);
- * (where string == "This is a test.")
- *
- * This call returns a pointer to:
- *
- * "is "
- *
- * An error code of -1 is returned is the `endpos' is greater than
- * `startpos'
- *
- *
- * Lance E. Shepard
- */
-
- char *
- substr1(string, start, end)
-
- char *string;
- int start;
- int end;
-
- {
-
- static char retstr[MAX_S];
- int loop1;
- int loop2;
-
- if (end < start) {
- exit(-1);
- }
-
- for (loop2 = 0; loop2 < MAX_S; loop2++)
- retstr[loop2] = NULL;
-
- for (loop1 = start, loop2 = 0; string[loop1] != NULL &&
- loop1 < end && loop2 <= MAX_S; loop1++, loop2++)
-
- retstr[loop2] = string[loop1];
-
- retstr[++loop2] = NULL;
-
- return(retstr);
-
- }
-
- /*
- * This is the function `char *expand().' This function takes as
- * an argument a NULL terminated string and replaces all occurances
- * of the tab character with 8 (eight) spaces. The function returns
- * a pointer to a static string which is overwritten on subsequent
- * calls.
- */
-
- char *
- expand(string)
-
- char *string;
-
- {
-
- int count;
- static char retstr[MAX_S];
-
- for (count = 0; count < MAX_S; retstr[count++] = NULL) ;
-
- for (count = 0; *string != NULL; count++, string++) {
-
- if (*string == '\t') {
- retstr[count] = ' ';
- /* while (((count + 1) % 8) != 0) */
- while (TabDef[count] != 'T')
- retstr[++count] = ' ';
- }
- else
- retstr[count] = *string;
- }
-
- retstr[count] = NULL;
-
- return(retstr);
-
- }
-
- char *Rs(s) /* strip trailing blanks from string */
- char s[];
- {
- int n;
-
- for (n=strlen(s)-1 ; n>=0 && isspace(s[n]) ; n--);
- s[n+1] = '\0';
- return(s);
- }
-
- int Cmemb(a,b) /* is character "a" a member of string "b" */
- char a, *b;
- {
- while (*b)
- if (a == *b++) return(1);
- if (!a) return(1);
- else return(0);
- }
-
-